#include "evm_cmd_handlers.h"
#include <stdio.h>

uint32_t evm_nop  ( evm_process *process ) {
    return EVM_OK;
}


uint32_t evm_push ( evm_process *process ) {
    int32_t res = 0;
    // here can be error, if pc and arg are on the bound of memory chunks
    res = evm_stack_push( process->data_stack, *((uint32_t*)(process->pc + 1)) );
    process->pc += 4; // replace with evm_process_pcadd( process, 4 );
    return res;
}


uint32_t evm_pop  ( evm_process *process ) {
    int32_t res = 0;
    res = evm_stack_pop( process->data_stack, 0 );
    return res;
}


uint32_t evm_stop ( evm_process *process ) {
    process->state = STOPPED;
    return EVM_OK;
}


uint32_t evm_add( evm_process *process ) {
    int32_t res = 0;
    int32_t val = 0, val1 = 0;

    res = evm_stack_pop( process->data_stack, &val );
    if ( res != EVM_OK ) {
        return res;
    }

    res = evm_stack_pop( process->data_stack, &val1 );
    if ( res != EVM_OK ) {
        return res;
    }

    val = val + val1;
    res = evm_stack_push( process->data_stack, val );

    return res;
}


uint32_t evm_sub  ( evm_process *process ) {
    int32_t res = 0;
    int32_t val = 0, val1 = 0;

    res = evm_stack_pop( process->data_stack, &val );
    if ( res != EVM_OK ) {
        return res;
    }

    res = evm_stack_pop( process->data_stack, &val1 );
    if ( res != EVM_OK ) {
        return res;
    }

    val = val1 - val;
    res = evm_stack_push( process->data_stack, val );

    return res;
}


uint32_t evm_mul  ( evm_process *process ) {
    int32_t res = 0;
    int32_t val = 0, val1 = 0;

    res = evm_stack_pop( process->data_stack, &val );
    if ( res != EVM_OK ) {
        return res;
    }

    res = evm_stack_pop( process->data_stack, &val1 );
    if ( res != EVM_OK ) {
        return res;
    }

    val = val1 * val;
    res = evm_stack_push( process->data_stack, val );

    return res;
}


uint32_t evm_div  ( evm_process *process ) {
    int32_t res = 0;
    int32_t val = 0, val1 = 0;

    res = evm_stack_pop( process->data_stack, &val );
    if ( res != EVM_OK ) {
        return res;
    }

    res = evm_stack_pop( process->data_stack, &val1 );
    if ( res != EVM_OK ) {
        return res;
    }

    val = val1 / val;
    res = evm_stack_push( process->data_stack, val );

    return res;
}


uint32_t evm_mod  ( evm_process *process ) {
    int32_t res = 0;
    int32_t val = 0, val1 = 0;

    res = evm_stack_pop( process->data_stack, &val );
    if ( res != EVM_OK ) {
        return res;
    }

    res = evm_stack_pop( process->data_stack, &val1 );
    if ( res != EVM_OK ) {
        return res;
    }

    val = val1 % val;
    res = evm_stack_push( process->data_stack, val );

    return res;
}


uint32_t evm_dbgdata( evm_process *process ) {
    evm_stack *s = process->data_stack;
    uint32_t  *p = s->sp - 1;
    uint32_t   i = 0;

    printf("\nDATA STACK BEGIN\n");
    while ( p != s->data - 1 ) {
        printf("%5.5d: %20d%20x\n", i, *p, *p );
        p -= 1;
        i = i + 1;
    }
    printf("DATA STACK END\n\n");

    return EVM_OK;
}
